﻿#region Copyright (c) 2000-2008 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{       AgDataGrid                                 }
{                                                                   }
{       Copyright (c) 2000-2008 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2008 Developer Express Inc.

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using DevExpress.AgDataGrid.Data;
using DevExpress.AgDataGrid.Utils;
using System.Diagnostics;
namespace DevExpress.AgDataGrid.Internal {
	public interface IRowsControllerOwner {
		Panel DataPanel { get; }
		int TopRow { get; set; }
		double PanelHeight { get; }
		double PanelWidth { get; }
		int RowCount { get; }
		double GetLinesWidth { get; }
		AgDataGridRowBase CreateVisibleRow(int handle);
		int GetRowHandleByVisibleIndex(int visibleIndex);
		int GetVisibleIndexByHandle(int handle);
		AgDataGridRowType GetRowType(int handle);
		AgDataGridRowState GetState(int handle);
	}
	public class AgRowsControllerRowState {
		RowsController Controller;
		public AgRowsControllerRowState(RowsController controller, int handle, AgDataGridRowState state, AgDataGridRowType rowType) {
			Controller = controller;
			State = state;
			RowType = rowType;
			Handle = handle;
		}
		public AgDataGridRowState State { get; private set; }
		public AgDataGridRowType RowType { get; private set; }
		public int Handle { get; private set; }
		AgDataGridRowBase Row {
			get {
				return Controller.GetVisibleRow(Controller.Owner.GetVisibleIndexByHandle(Handle));
			}
		}
		internal void UpdateCellState(AgDataGridCell cell) {
			if (Row != null) {
				Row.UpdateCellState(cell);
			}
		}
		internal void CalcRowState() {
			if (Row != null) {
				Row.CalcRowState();
			}
		}
	}
	public class RowsController {
		IRowsControllerOwner owner;
		int topRowVisibleIndex;
		internal List<int> NewHandlersList = new List<int>();
		internal List<int> OldHandlersList = new List<int>();
		List<AgDataGridRow> FreeDataRows = new List<AgDataGridRow>();
		List<AgDataGridGroupRow> FreeGroupRows = new List<AgDataGridGroupRow>();
		internal List<AgDataGridRowBase> VisibleRows = new List<AgDataGridRowBase>();
		public RowsController(IRowsControllerOwner owner) {
			this.owner = owner;
		}
		double PanelHeight { get { return Owner.PanelHeight; } }
		public IRowsControllerOwner Owner { get { return owner; } }
		public virtual Panel DataPanel { get { return Owner.DataPanel; } }
		public int TopRowVisibleIndex {
			get { return topRowVisibleIndex; }
			set {
				if (TopRowVisibleIndex == value) return;
				topRowVisibleIndex = value >= Owner.RowCount ? Owner.RowCount - 1 : value;
				PerformLayout();
				PerformVisibleElementsLayout();
			}
		}
		public bool IsLastRowVisible {
			get {
				double h = 0;
				if (VisibleRows.Count == 0)
					return false;
				foreach (AgDataGridRowBase item in VisibleRows) {
					h += MeasureRowAfterAnimation(item);
				}
				return h <= Owner.PanelHeight;
			}
		}
		public int LastVisibleElementIndex { get { return TopRowVisibleIndex + GetVisibleRowCount() - 1; } }
		double heightWithoutLastElement = 0;
		internal double PerformVisibleElementsLayout(int count) {
			BuildHandlersList(count);
			BuildRowLists();
			double height = 0;
			VisibleRows.Clear();
			for (int i = 0; i < NewHandlersList.Count; i++) {
				int handle = NewHandlersList[i];
				AgDataGridRowBase row = GetRow(handle);
				OrderPanelBase.SetVisibleIndex(row, i);
				VisibleRows.Add(row);
				heightWithoutLastElement = height;
				height += MeasureRow(row);
				if (height > PanelHeight) break;
			}
			((Panel)DataPanel).MeasureEx(new Size(double.PositiveInfinity, double.PositiveInfinity));
			((Panel)DataPanel).InvalidateMeasure();
			return height;
		}
		internal void PerformLayout() {
			if (DataPanel == null) return;
			double h = PerformVisibleElementsLayout(VisibleRows.Count);
			while (h < PanelHeight && (Owner.RowCount > TopRowVisibleIndex + VisibleRows.Count)) {
				h = PerformVisibleElementsLayout(VisibleRows.Count + 1);
			}
		}
		private void BuildHandlersList(int count) {
			OldHandlersList.Clear();
			OldHandlersList.AddRange(NewHandlersList);
			NewHandlersList.Clear();
			for (int i = 0; i < count; i++) {
				int visibleIndex = TopRowVisibleIndex + i;
				int handle = Owner.GetRowHandleByVisibleIndex(visibleIndex);
				if (handle == DataController.InvalidRow) continue;
				NewHandlersList.Add(handle);
			}
		}
		public void PerformVisibleElementsLayout() {
			for (int i = 0; i < GetVisibleRowCount(); i++) {
				IElementPerformLayout layout = GetVisibleRow(TopRowVisibleIndex + i) as IElementPerformLayout;
				if (layout != null) layout.PerformVisualLayout();
			}
		}
		public void Reset() {
			DataPanelClearChildren();
		}
		protected virtual void DataPanelClearChildren() {
			if (DataPanel == null) return;
			foreach (UIElement elem in DataPanel.Children) {
				RaiseBeforeRemove(elem);
			}
			DataPanel.Children.Clear();
		}
		protected virtual void RaiseBeforeRemove(UIElement elem) {
			IElementPerformLayout layout = elem as IElementPerformLayout;
			if (layout == null) return;
			layout.BeforeRemove();
		}
		public int GetVisibleRowCount() {
			return VisibleRows.Count - (IsLastRowVisible ? 0 : 1);
		}
		public virtual double MeasureRowAfterAnimation(FrameworkElement element) {
			if (element == null) return 0;
			IElementPerformLayout layout = element as IElementPerformLayout;
			if (layout != null) {
				double res = layout.HeightAfterAnimation;
				if (res != 0.0) return res + Owner.GetLinesWidth;
			}
			return MeasureRow(element);
		}
		protected virtual double MeasureRow(FrameworkElement element) {
			if (DataPanel == null) return AgDataGrid.DefaultRowHeight;
			element.InvalidateMeasureEx();
			if (VisualTreeHelper.GetParent(element) != null) {
				if (element.DesiredSize.Height == 0) {
					element.Measure(new Size(Owner.PanelWidth, double.PositiveInfinity));
				}
				return element.DesiredSize.Height + Owner.GetLinesWidth;
			} else return element.Height + Owner.GetLinesWidth;
		}
		int FindHandleInDataPanel(int handle) {
			for (int i = 0; i < DataPanel.Children.Count; i++) {
				AgDataGridRowBase row = DataPanel.Children[i] as AgDataGridRowBase;
				if (row == null) continue;
				if (row.Handle == handle) return i;
			}
			return -1;
		}
		void ApplyRowValue(AgDataGridRowBase row, int handle) {
			row.Handle = handle;
		}
		public AgDataGridRowBase GetVisibleRow(int visibleIndex) {
			if (VisibleRows.Count > visibleIndex - TopRowVisibleIndex && visibleIndex - TopRowVisibleIndex >= 0) {
				return VisibleRows[visibleIndex - Owner.TopRow];
			}
			return null;
		}
		public AgRowsControllerRowState GetRowState(int handle) {
			AgDataGridRowBase row = GetVisibleRow(Owner.GetVisibleIndexByHandle(handle));
			return new AgRowsControllerRowState(this, handle, GetState(row, handle), Owner.GetRowType(handle));
		}
		AgDataGridRowState GetState(AgDataGridRowBase row, int handle) {
			if (row == null) {
				return Owner.GetState(handle);
			}
			return row.State;
		}
		public double GetRowHeight(int visibleIndex) {
			return MeasureRowAfterAnimation(GetVisibleRow(visibleIndex));
		}
		internal void BuildRowLists() {
			FreeDataRows.Clear();
			FreeGroupRows.Clear();
			foreach (FrameworkElement elem in DataPanel.Children) {
				AgDataGridRowBase row = elem as AgDataGridRowBase;
				if (row == null) continue;
				if (!NewHandlersList.Contains(row.Handle)) {
					OrderPanelBase.SetVisibleIndex(row, -1);
					if (row.Handle < 0)
						FreeGroupRows.Add((AgDataGridGroupRow)row);
					else {
						FreeDataRows.Add((AgDataGridRow)row);
					}
				}
			}
		}
		AgDataGridRowBase GetRow(int handle) {
			int index = FindHandleInDataPanel(handle);
			if (index >= 0)
				return (AgDataGridRowBase)DataPanel.Children[index];
			return GetFreeRow(handle);
		}
		AgDataGridRowBase GetFreeRow(int handle) {
			AgDataGridRowBase row = handle < 0 ? GetFreeGroupRow(handle) : GetFreeDataRow(handle);
			if (row == null) {
				row = Owner.CreateVisibleRow(handle);
				DataPanel.Children.Add(row);
			} else {
				ApplyRowValue(row, handle);
			}
			return row;
		}
		private AgDataGridRowBase GetFreeDataRow(int handle) {
			if (FreeDataRows.Count > 0) {
				AgDataGridRowBase row = FreeDataRows[0];
				FreeDataRows.RemoveAt(0);
				return row;
			}
			return null;
		}
		private AgDataGridRowBase GetFreeGroupRow(int handle) {
			if (FreeGroupRows.Count > 0) {
				AgDataGridRowBase row = FreeGroupRows[0];
				FreeGroupRows.RemoveAt(0);
				return row;
			}
			return null;
		}
		void UpdateDataPanel() {
		}
	}
}
